/*
 * This file is part of the Try! Engine project.
 *
 * Copyright 2010-2011 Emanuele Bertoldi. All rights reserved.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * You should have received a copy of the modified BSD License along with this
 * program. If not, see <http://www.opensource.org/licenses/bsd-license.php>
 */

#include "projecttree.h"
#include "ui_projecttree.h"
#include <projectmodellist.h>
#include <QtGui/QMenu>

using namespace Try;

ProjectTree::ProjectTree(QWidget* parent)
    :   QWidget(parent),
        m_ui(new Ui::ProjectTree),
        m_contextItem(0)
{
    m_ui->setupUi(this);

    this->setEnabled(false);
    this->setAcceptDrops(true);

    QObject::connect(ProjectModelList::instance(), SIGNAL(projectLoaded(Project*)), this, SLOT(onProjectLoaded(Project*)));
    QObject::connect(ProjectModelList::instance(), SIGNAL(projectClosed(Project*)), this, SLOT(onProjectClosed(Project*)));
    QObject::connect(ProjectModelList::instance(), SIGNAL(projectChanged(Project*)), this, SLOT(onProjectChanged(Project*)));
    QObject::connect(ProjectModelList::instance(), SIGNAL(projectSelectionChanged(Project*)), this, SLOT(onProjectSelectionChanged(Project*)));

    QObject::connect(m_ui->treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequest(QPoint)));
    QObject::connect(m_ui->treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(onCurrentItemChanged()));
}

ProjectTree::~ProjectTree()
{
    delete m_ui;
}

QTreeWidgetItem* ProjectTree::rootItem() const
{
    return m_ui->treeWidget->topLevelItem(0);
}

bool ProjectTree::isProjectItem(QTreeWidgetItem* item) const
{
    return (item == this->rootItem());
}

bool ProjectTree::isObjectItem(QTreeWidgetItem* item) const
{
    if (item)
        return this->isProjectItem(item->parent());

    return false;
}

bool ProjectTree::isPropertyItem(QTreeWidgetItem* item) const
{
    if (item)
        return this->isObjectItem(item->parent());

    return false;
}

void ProjectTree::onProjectLoaded(Project* project)
{
    m_ui->treeWidget->clear();

    if (project)
    {
        QTreeWidgetItem* root = new QTreeWidgetItem(QStringList(project->name()));

        ObjectList objects = project->objects();
        int obj_count = objects.size();

        for (int i=0; i<obj_count; i++)
        {
            Object* obj = objects.at(i);

            QTreeWidgetItem* item = new QTreeWidgetItem(QStringList(obj->name().c_str()));

            PropertyList properties = obj->properties();
            int prop_count = properties.size();

            for (int j=0; j<prop_count; j++)
            {
                Property* prop = properties.at(j);

                item->addChild(new QTreeWidgetItem(QStringList(prop->name().c_str())));
            }

            root->addChild(item);
        }

        m_ui->treeWidget->addTopLevelItem(root);

        root->setSelected(true);
    }

    m_ui->treeWidget->expandAll();

    this->setEnabled(true);
}

void ProjectTree::onProjectClosed(Project* project)
{
    Q_UNUSED(project)

    m_ui->treeWidget->clear();

    this->setEnabled(false);
}

void ProjectTree::onProjectChanged(Project* project)
{
    // TODO: a smarter logic.
    this->onProjectLoaded(project);
}

void ProjectTree::onProjectSelectionChanged(Project* project)
{
    if (project)
    {
        QList<QTreeWidgetItem*> old_items = m_ui->treeWidget->selectedItems();
        QList<QTreeWidgetItem*> new_items;

        foreach (Object* obj, project->selectedObjects())
        {
            int id = project->objectIdFromName(obj->name());

            QTreeWidgetItem* item = this->rootItem()->child(id);
            item->setSelected(true);

            new_items.append(item);
        }

        foreach (QTreeWidgetItem* item, old_items)
            item->setSelected(new_items.contains(item));

        if (new_items.isEmpty() && m_ui->treeWidget->topLevelItemCount() > 0)
            this->rootItem()->setSelected(true);
    }
}

void ProjectTree::onAddObjectAction()
{
    Project* project = ProjectModelList::instance()->projectAt(0);

    if (project)
        project->createObject();
}

void ProjectTree::onCopyObjectAction()
{
    Project* project = ProjectModelList::instance()->projectAt(0);

    if (project)
    {
        int row = this->rootItem()->indexOfChild(m_contextItem);

        project->copyObject(row);
    }
}

void ProjectTree::onDeleteObjectAction()
{
    Project* project = ProjectModelList::instance()->projectAt(0);

    if (project)
    {
        int row = this->rootItem()->indexOfChild(m_contextItem);

        Object* obj = project->object(row);
        if (obj)
        {
            obj->deleteAllProperties();
            project->deleteObject(obj);
        }
    }
}

void ProjectTree::onDeletePropertyAction()
{
    Project* project = ProjectModelList::instance()->projectAt(0);

    if (project)
    {
        QTreeWidgetItem* obj_item = m_contextItem->parent();

        int obj_row = this->rootItem()->indexOfChild(obj_item);
        int prop_row = obj_item->indexOfChild(m_contextItem);

        Object* obj = project->object(obj_row);

        if (obj)
            obj->deleteProperty(prop_row);
    }
}

void ProjectTree::onCustomContextMenuRequest(const QPoint& point)
{
    m_contextItem = m_ui->treeWidget->itemAt(point);

    QMenu menu(this);

    if (m_contextItem)
    {
        m_contextItem->setSelected(true);

        // Project.
        if (this->isProjectItem(m_contextItem))
        {
            menu.addAction(tr("&Add object"), this, SLOT(onAddObjectAction()));
        }

        // Object selected.
        else if (this->isObjectItem(m_contextItem))
        {
            menu.addAction(tr("&Copy object"), this, SLOT(onCopyObjectAction()));
            menu.addAction(tr("&Delete object"), this, SLOT(onDeleteObjectAction()));
        }

        // Property selected.
        else if (this->isPropertyItem(m_contextItem))
        {
            menu.addAction(tr("&Delete property"), this, SLOT(onDeletePropertyAction()));
        }
    }
    else
    {
        m_ui->treeWidget->clearSelection();
    }

    menu.exec(m_ui->treeWidget->mapToGlobal(point));
}

void ProjectTree::onCurrentItemChanged()
{
    Project* project = ProjectModelList::instance()->projectAt(0);

    if (project)
    {
        project->deselectAllObjects();

        QTreeWidgetItem* item = m_ui->treeWidget->currentItem();

        if (item)
        {
            // Project.
            if (this->isProjectItem(item))
            {
                // Do nothing.
            }

            // Object.
            else if (this->isObjectItem(item))
            {
                int index = this->rootItem()->indexOfChild(item);

                Object* object = project->object(index);

                project->selectObject(object);
            }

            // Property.
            else if (this->isPropertyItem(item))
            {
                int obj_index = this->rootItem()->indexOfChild(item->parent());
                int index = item->parent()->indexOfChild(item);

                Object* object = project->object(obj_index);

                /*
                if (object)
                {
                    Property* prop = object->property(index);

                    // Do nothing.
                }
                */

                project->selectObject(object);
            }
        }
    }
}
